home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Language/OS - Multiplatform Resource Library
/
LANGUAGE OS.iso
/
oper_sys
/
presto
/
prest1_0.lha
/
src
/
process.h
< prev
next >
Wrap
C/C++ Source or Header
|
1991-12-11
|
8KB
|
294 lines
#ifndef __presto__process_h__
#define __presto__process_h__
//
//
// Processes work as hungry puppies, banging on the scheduler
// until a ready job is available or until someone bangs on the
// process asking it to do something "out of band" (like pausing
// or dying).
//
// Modification History:
//
// 05-Dec-89 John Faust
// Remove stack free list. Allocate stacks of fixed size when thread
// is allocated. Stack remains associated with owning thread. More
// efficient (removes search of stack freelist for stack of proper size,
// allocation of stack if one of proper size not found, and eliminates
// need to balance local stack freelists).
//
// 08-Nov-1989 John Faust
// Implement per-processor free lists of thread templates.
//
extern Process *sysproc;
class Invocation;
//
// Default maximum size of global thread freelist, threshhold of local list,
// and number of threads to preallocate for local freelists.
// Note that currently, thread size is 132 bytes.
//
// Using these values, the Create1M benchmark never has to allocate any threads
// once the processes have been initialized.
//
#define GBL_THREAD_FREELIST_MAX 128
#define LCL_THREAD_FREELIST_THRESH 8
#define NUM_PREALLOC_THREADS 4
extern shared_t int gbl_thread_freelist_max;
extern shared_t int lcl_thread_freelist_thresh;
class Process : public Object {
#if (sun && THREAD_HAS_INTERRUPTIBLE_FIELD)
int p_interruptible;
#endif
#ifdef vax
// WARNING: The offset of p_interruptible is known to swtch().
int p_interruptible;
#endif /* vax */
#ifdef mips
// CAVEAT: swtch() for mips doesn't use this
int p_interruptible;
#endif
char *p_name; // my name
int p_id; // my id
// WARNING: The offset of p_pid is known in hc_slock_asm.h
int p_pid; // system pid
int p_ppid; // system ppid
//
// Get and free threads from global shared thread freelist.
// Processes go to the list only when their local freelist becomes
// empty or when it gets to full.
//
void get_gbl_threads ();
void free_gbl_threads ();
protected:
int p_state; // whats up
int p_flags; // long term process stuff
int p_request; // stop spinning on this
Thread *p_schedthread; // where to swtch back to
Thread *p_thread; // currently running thread
ThreadQUnlocked* p_thread_freelist; // per-processor thd freelist
#define NEWPROCESS
virtual void p_fork(); // take care of the fork
virtual void p_wait(); // where we spin
virtual void p_pause(); // internal ::pause
virtual void p_runchild(int *spinflag); // copy stack and go
public:
Process(int ptag, int id);
Process();
Process(char* name, int id, int delayedfork = 0); // fork in ctor
virtual ~Process();
// virtual newprocess function. After creation of the first thisproc,
// raw process constructor is not used. thisproc->newprocess() is
// used instead. User can assign his own derivation of Process to
// thisproc in Main::init().
virtual Process* newprocess(char* name,int id);
// Processes, like threads, are not deallocated when destroyed
// The wisdom of this design is beyond me. PBD.
void *operator new (size_t s) {
return ::operator new(s);
}
void operator delete(void *) {} // do not reclaim allocated space
virtual int request(int req);
virtual void park(); // os pause
virtual void drive(); // resume
virtual int invoke();
//
// Get and free threads from per-processor freelist.
//
inline Thread* get_thread (int* init_reqd);
inline void free_thread (Thread* t);
int state()
{ return p_state; }
void setstate(int st)
{ p_state = st; }
int flags()
{ return p_flags; }
inline int isroot();
int id() // scheduler id
{return p_id; }
int pid() // unix id
{ return p_pid; }
int ppid() // unix parent id
{ return p_ppid; }
char * name()
{ return p_name; }
Thread *schedthread()
{ return p_schedthread; }
Thread *runningthread()
{ return p_thread; }
#if (sun && THREAD_HAS_INTERRUPTIBLE_FIELD)
int interruptible()
{ return p_interruptible; }
inline int disable_interrupts();
void enable_interrupts()
{ p_interruptible = 1; }
#endif /* sun */
#ifdef vax
int interruptible()
{ return p_interruptible; }
inline int disable_interrupts();
void enable_interrupts()
{ p_interruptible = 1; }
#endif /* vax */
#ifdef mips
int interruptible()
{ return p_interruptible; }
inline int disable_interrupts();
void enable_interrupts()
{ p_interruptible = 1; }
#endif /* mips */
virtual void print(ostream& = cout);
virtual void error(char *s);
};
#define R_NULL 0x00 /* nothing is happening */
#define R_WAKEUP 0x01 /* wakeup wherever you are */
#define R_PARK 0x02 /* put yourself to sleep in the OS */
#define R_DIE 0x04 /* the nice way to kill a process */
#define R_RETURN 0x08 /* relinquish control */
/*
* We don't need R_DIE and R_RETURN since the process wait routine
* only understands how to R_RETURN from its scheduling loop. Where
* it returns to is completely determined by how it was invoked.
* If it was invoked from runchild, then we will return to there
* and get nuked with a (delete this). If we were called via runrun
* from the Main constructor, then we will return to single threaded
* control.
*/
#define S_RUN 0x01 /* running */
#define S_WAIT 0x02 /* unused. waiting to be used in spinloop */
#define S_SLEEP 0x04 /* sleeping on an event */
#define S_OSPAUSE 0x08 /* WAITing or SLEEPing via OS pause */
#define S_FREE (S_WAIT|S_OSPAUSE)
#define S_ZOMBIE 0x10
#define S_EXITING 0x20
#define S_DELAYEDFORK 0x40 /* constructed, but not yet forked */
#define S_FORKING 0x80 /* as we speak... */
#define S_ERROR 0x100
#define S_REAPED 0x200 /* already cleaned up */
#define S_REAPING 0x400 /* parent process cleaning up */
//
// special proc tags for flags field
//
#define P_ROOT 0x01
inline int Process::isroot()
{
return (p_flags&P_ROOT);
}
//
// Get a thread from the process freelist. This is an unshared, unprotected
// queue, so access to it should be very fast.
//
inline Thread*
Process::get_thread (int* init_reqd)
{
Thread* t;
// If called before Process context is established,
// just return a newly allocated Thread and say that
// it needs initializing
if (this == 0)
{
*init_reqd = 1;
return (t = (Thread *) new char [sizeof(Thread)]);
}
//
// If this process' local freelist is exhausted, then try to grab some
// more threads from the global queue.
//
if (p_thread_freelist->length() == 0)
get_gbl_threads ();
//
// Check local freelist for reuseable thread. If none, allocate
// a new one.
//
t = p_thread_freelist->get ();
if (t)
{
*init_reqd = 0;
return t;
}
else
{
*init_reqd = 1;
return (t = (Thread*) new char [sizeof (Thread)]);
}
}
//
// Return a thread to the local freelist for this process.
//
inline void
Process::free_thread (Thread* t)
{
p_thread_freelist->append (t);
//
// If the local freelist is over threshhold, move half it's threads
// to the global freelist.
//
if (p_thread_freelist->length() > lcl_thread_freelist_thresh)
free_gbl_threads ();
}
#if (sun && THREAD_HAS_INTERRUPTIBLE_FIELD)
inline int Process::disable_interrupts()
{
if (p_interruptible) {
p_interruptible = 0;
return 1;
} else
return 0;
}
#endif /* sun */
#ifdef vax
inline int Process::disable_interrupts()
{
if (p_interruptible) {
p_interruptible = 0;
return 1;
} else
return 0;
}
#endif /* vax */
#ifdef mips
inline int Process::disable_interrupts()
{
if (p_interruptible) {
p_interruptible = 0;
return 1;
} else
return 0;
}
#endif /* mips */
extern private_t Process *thisproc; // private to each proc
#endif /* __presto__process_h__ */